<?php

/**
 * This file is part of the Codizer package.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @copyright   Copyright (c) 2010 Advisa (http://www.advisa.fr)
 * @author      Codizer Core Team <team@codizer.org>
 * @package     Codizer
 */

class f_builder_TranslationParser
{
    public static $DEFAULT_TPL_LANG = 'en';
    private $cleanObsolete = false;

    /**
	 * @return f_builder_TranslationParser
	 */
	private function __construct()
	{
		return $this;
	}

	/**
	 * Get instance
	 *
	 * @return f_builder_TranslationParser
	 */
	public static function getInstance()
	{
		return new self();
	}

    public function parseTemplatesTranslations($langTo, $module, $cleanObsolete = false)
    {
        $this->cleanObsolete = $cleanObsolete;

        $stats1 = $this->parseModulesTemplates($langTo, MODULES_DIR, $module);
        $stats2 = $this->parseModulesTemplates($langTo, WEBAPP_MODULES_DIR, $module);

        $new = $stats1['new'] + $stats2['new'];
        $exist = $stats1['exist'] + $stats2['exist'];
        $obsolete = $stats1['obsolete'] + $stats2['obsolete'];
        $notTranslated = $stats1['notTranslated'] + $stats2['notTranslated'];

        if(CLI_MODE)
        {
            echo COLOR_GREEN."New           ".COLOR_NORMAL." -> $new\n";
            echo COLOR_GREEN."Obsolete      ".COLOR_NORMAL." -> $obsolete\n";
            echo COLOR_GREEN."Not translated".COLOR_NORMAL." -> $notTranslated\n";
            echo COLOR_GREEN."Exist         ".COLOR_NORMAL." -> $exist\n";
        }
    }

    private function parseModulesTemplates($langTo, $mainFolder = MODULES_DIR, $moduleToParse)
    {
        if(!is_null($moduleToParse))
        {
            return $this->parseModuleTemplates($mainFolder, $moduleToParse, $langTo);
        }

        $result = array();
        $result['new'] = 0;
        $result['exist'] = 0;
        $result['obsolete'] = 0;
        $result['notTranslated'] = 0;

        // Get all modules in main folder (modules dir or webapp)
        $modules = $this->getModulesName($mainFolder);        

        if(is_array($modules) && count($modules) > 0)
        {
            foreach($modules as $module)
            {
                $stats = $this->parseModuleTemplates($mainFolder, $module, $langTo);
                $result['new'] += $stats['new'];
                $result['exist'] += $stats['exist'];
                $result['obsolete'] += $stats['obsolete'];
                $result['notTranslated'] += $stats['notTranslated'];
            }
        }

        return $result;
    }

    private function parseModuleTemplates($mainFolder, $module, $langTo)
    {
        $fileResolver = f_file_Resolver::getInstance();

        $xml_stats = array();
        $xml_stats['new'] = 0;
        $xml_stats['exist'] = 0;
        $xml_stats['obsolete'] = 0;
        $xml_stats['notTranslated'] = 0;

        // Get all templates files paths
        $tplFiles = $fileResolver->fromDirectory($mainFolder.DS.$module.DS.'templates')->setMask('*.html')->setRecursive(true)->find();

        if(is_array($tplFiles) && count($tplFiles) > 0)
        {
            $templates = $this->orderTemplatesByLangs($tplFiles);
        }

        if(isset($templates) && is_array($templates) && count($templates) > 0)
        {
            
            foreach($templates as $langFrom => $files)
            {
                if($langFrom != $langTo)
                {
                    // Get translation xml file path
                    $xmlFile = $mainFolder.DS.$module.DS.'locales'.DS.$langTo.DS.'from_'.$langFrom.'.xml';

                    $inXml = array();
                    $inXml['source'] = array();
                    $inXml['target'] = array();

                    if(is_file($xmlFile))
                    {
                        $xml = f_xml_Xpath::getInstance($xmlFile);
                        $sources = $xml->getElementsFromXpath('locale');

                        if(count($sources) > 0)
                        {
                            foreach($sources as $source)
                            {
                                /*@var $source f_xml_XmlElement */
                                $inXml['source'][] = $source->getSubElement('source')->getContent();
                                $inXml['target'][] = $source->getSubElement('target')->getContent();
                            }
                        }
                    }

                    $locales = array();

                    foreach($files as $file)
                    {
                        $sources = $this->getTranslationsSourcesFromTemplate($file);

                        if(!is_null($sources) && is_array($sources) && count($sources) > 0)
                        {
                            foreach($sources as $source)
                            {
                                $locales[] = $source;
                            }
                        }
                    }

                    if(count($locales) > 0)
                    {
                        $xml = $this->makeXML($langFrom, $langTo, array_unique($locales), $inXml);
                        $this->writeXML($mainFolder, $module, $langFrom, $langTo, $xml['content']);
                        foreach($xml['stats'] as $key => $value)
                        {
                            if(isset($xml_stats[$key]))
                            $xml_stats[$key] = $xml_stats[$key]+$value;
                            else
                            $xml_stats[$key] = $value;
                        }
                        
                    }
                }
            }
            return $xml_stats;
        }
    }

    private function writeXML($mainFolder, $module, $langFrom, $langTo, $xmlContent)
    {
        $path = $mainFolder.DS.$module.DS.'locales'.DS.$langTo;
        $filePath = $path.DS.'from_'.$langFrom.'.xml';

        if(!is_dir($path))
        {
            mkdir($path, 0777, true);
        }

        $fh = fopen($filePath, 'w');

        fwrite($fh, $xmlContent);
        fclose($fh);
    }

    private function makeXML($langFrom, $langTo, $locales, $inXml)
    {
        $result = array();

        $xml = new XMLWriter();
        $xml->openMemory();
        $xml->setIndent(true);
        $xml->setIndentString('    ');
        $xml->startDocument('1.0', 'UTF-8');
        $xml->startElement('locales');
        $xml->writeAttribute('source', $langFrom);
        $xml->writeAttribute('target', $langTo);

        $new = 0;
        $exist = 0;
        $obsolete = 0;
        $notTranslated = 0;

        foreach($locales as $locale)
        {
            if($locale != '')
            {
                if(!in_array($locale, $inXml['source']))
                {
                    $xml->startElement('locale');
                    $crc = sprintf('%u', crc32($locale));
                    $xml->writeAttribute('crc', $crc);
                    $xml->startElement('source');
                    if(strpos($locale, '<') || strpos($locale, '>') || strpos($locale, '&'))
                    {
                        $xml->writeCdata($locale);
                    }
                    else
                    {
                        $xml->writeRaw($locale);
                    }
                    $xml->endElement();
                    $xml->startElement('target');
                    if(strpos($locale, '<') || strpos($locale, '>') || strpos($locale, '&'))
                    {
                        $xml->writeCdata('');
                    }
                    else
                    {
                        $xml->writeRaw('');
                    }
                    $xml->endElement();
                    $xml->endElement();
                    $notTranslated++;
                    $new++;
                }
                else
                {
                    $k = array_search($locale, $inXml['source']);

                    $xml->startElement('locale');
                    $crc = sprintf('%u', crc32($locale));
                    $xml->writeAttribute('crc', $crc);
                    $xml->startElement('source');
                    if(strpos($locale, '<') || strpos($locale, '>') || strpos($locale, '&'))
                    {
                        $xml->writeCdata($locale);
                    }
                    else
                    {
                        $xml->writeRaw($locale);
                    }
                    $xml->endElement();
                    $xml->startElement('target');
                    if(strpos($inXml['target'][$k], '<') || strpos($inXml['target'][$k], '>') || strpos($inXml['target'][$k], '&'))
                    {
                        $xml->writeCdata($inXml['target'][$k]);
                    }
                    else
                    {
                        $xml->writeRaw($inXml['target'][$k]);
                    }
                    $xml->endElement();
                    $xml->endElement();

                    if($inXml['target'][$k] == '')
                    {
                        $notTranslated++;
                    }

                    unset($inXml['source'][$k]);
                    unset($inXml['target'][$k]);
                    $exist++;
                }
            }
        }

        if(count($inXml['source']) > 0 && $this->cleanObsolete == false)
        {
            $xml->writeComment(' ==== OBSOLETE CONTENT ==== ');
            $xml->endComment();
            foreach($inXml['source'] as $k => $locale)
            {
                $xml->startElement('locale');
                $crc = sprintf('%u', crc32($locale));
                $xml->writeAttribute('crc', $crc);
                $xml->writeAttribute('obsolete', true);
                $xml->startElement('source');
                if(strpos($locale, '<') || strpos($locale, '>') || strpos($locale, '&'))
                {
                    $xml->writeCdata($locale);
                }
                else
                {
                    $xml->writeRaw($locale);
                }
                $xml->endElement();
                $xml->startElement('target');
                if(strpos($inXml['target'][$k], '<') || strpos($inXml['target'][$k], '>') || strpos($inXml['target'][$k], '&'))
                {
                    $xml->writeCdata($inXml['target'][$k]);
                }
                else
                {
                    $xml->writeRaw($inXml['target'][$k]);
                }
                $xml->endElement();
                $xml->endElement();
                $obsolete++;
            }
        }

        $xml->endElement();
        $xml->endDocument();

        $result['stats']['new'] = $new;
        $result['stats']['exist'] = $exist;
        $result['stats']['notTranslated'] = $notTranslated;
        $result['stats']['obsolete'] = $obsolete;
        $result['content'] =  $xml->outputMemory();

        return $result;
    }

    private function orderTemplatesByLangs($files)
    {
        $ordered = array();

        foreach($files as $file)
        {
            $content = @file_get_contents($file);

            preg_match_all("/{\s*(setTplParams)\s*([^}]*)}/", $content, $matches);

            if(isset($matches[0][0]))
            {
                preg_match('`lang="(.*?)"`', $matches[0][0], $lang);
                
                if(isset($lang[1]))
                {
                    $ordered[$lang[1]][] = $file;
                }
                else
                {
                    $ordered[self::$DEFAULT_TPL_LANG][] = $file;
                }
            }
            else
            {
                $ordered[self::$DEFAULT_TPL_LANG][] = $file;
            }
        }

        return $ordered;
    }

    private function getTranslationsSourcesFromTemplate($file)
    {
        $content = @file_get_contents($file);

        if (empty($content))
        {
            return;
        }

        preg_match_all("/{\s*(t)\s*([^}]*)}([^{]*){\/\\1}/", $content, $matches);

        if(count($matches[0]) > 0)
        {
            return $matches[3];
        }
    }

    private function getModulesName($folder)
    {
        $modulesDir = f_file_Directory::getInstance($folder)->getSubdirs();

		$modules = array();

		foreach($modulesDir as $moduleDir)
		{
            /* @var $moduleDir f_file_Directory */
            if($moduleDir->getDirName() != '.svn')
            {
                $modules[] = $moduleDir->getDirName();
            }
        }

        return $modules;
    }
}
